package gupao.concurrency.api.sample;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Slf4j
public final class TBApiContextCache
{

	private static TBApiContextCache cache;

	/**
	 * API 调用日志缓存
	 * {@link ApiExecutorService}
	 */
	private ThreadLocal<List<ApiInvokeInfo>> apiInvokeInfoCache = new ThreadLocal<>();

	public static TBApiContextCache get()
	{
		if (TBApiContextCache.cache == null) {
			synchronized (TBApiContextCache.class) {
				if (TBApiContextCache.cache == null) {
					TBApiContextCache.cache = new TBApiContextCache();
					TBApiContextCache.cache.init();
				}
			}
		}
		return TBApiContextCache.cache;
	}

	//sessionkey--->time in millis
	private Map<String, Long> invalidSessionKeyCache = new WeakHashMap<>();

	private int schedulerThreadSize = 1;

	private long timeBeetweenTaskCheck = 25 * 60 * 1000;//45 minutes

	private long invalidTaskTimeInteval = timeBeetweenTaskCheck * 2;

	private final ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(schedulerThreadSize);

	public void init()
	{
		scheduler.scheduleAtFixedRate(new Runnable() {
			@Override
			public void run()
			{
				try {
					log.info("Has {} invalid sessionkeys before clean.", invalidSessionKeyCache.size());
					String[] keySet = invalidSessionKeyCache.keySet().toArray(new String[0]);
					long nowTime = new Date().getTime();
					for (String key : keySet) {
						Long val = invalidSessionKeyCache.get(key);
						if (val != null && nowTime - val >= invalidTaskTimeInteval) {
							invalidSessionKeyCache.remove(key);
						}
					}
					log.info("Has {} invalid sessionkeys after clean.", invalidSessionKeyCache.size());
				}
				catch (Exception e) {
					log.error("", e);
				}
			}
		}, timeBeetweenTaskCheck, timeBeetweenTaskCheck, TimeUnit.MILLISECONDS);
	}

	public void cacheInvalidSessionkey(String sessionkey)
	{
		if (StringUtils.hasLength(sessionkey))
			return;
		log.info("Cache invalid sessionkey '{}', totally cached {}", sessionkey, invalidSessionKeyCache.size());
		invalidSessionKeyCache.put(sessionkey, new Date().getTime());
	}

	public boolean isInvalidSessionkey(String sessionkey)
	{
		return invalidSessionKeyCache.containsKey(sessionkey);
	}

	public void addApiInvokeInfo(ApiInvokeInfo info)
	{
		List<ApiInvokeInfo> list = apiInvokeInfoCache.get();
		if (list == null) {
			list = new ArrayList<ApiInvokeInfo>();
			apiInvokeInfoCache.set(list);
		}
		list.add(info);
	}

	public void addAllApiInvokeInfo(List<ApiInvokeInfo> infos)
	{
		List<ApiInvokeInfo> list = apiInvokeInfoCache.get();
		if (list == null) {
			list = new ArrayList<ApiInvokeInfo>();
			apiInvokeInfoCache.set(list);
		}
		list.addAll(infos);
	}

	/**
	 * 客户端调用完API之后 "在调用线程内 " 获取到API调用日志
	 * @return
	 */
	public List<ApiInvokeInfo> getApiInvokeInfo()
	{
		return apiInvokeInfoCache.get();
	}

	/**
	 * 获取并清理API调用日志缓存
	 * 
	 * @return
	 */
	public List<ApiInvokeInfo> getAndCleanApiInvokeInfo()
	{
		List<ApiInvokeInfo> list = apiInvokeInfoCache.get();
		apiInvokeInfoCache.remove();
		if (list == null) {
			list = new ArrayList<ApiInvokeInfo>();
		}
		return list;
	}

	/**
	 * 清理API调用日志缓存
	 */
	public void cleanApiInvokeInfo()
	{
		apiInvokeInfoCache.remove();
	}
}
